#pragma once

#include "basic_config.hpp"

namespace zuck
{
	class ref_count {
	public:
		using cnt_type = zuck::size_t;
	public:
		constexpr ref_count(const zuck::size_t c = 0)
			: _m_cnt(c) {}

		constexpr ref_count(const ref_count& other)
			: _m_cnt(other._m_cnt) {}

		constexpr ref_count(ref_count&& other)noexcept
			: _m_cnt(other._m_cnt)
		{
			other._m_cnt = 0;
		}

		~ref_count()
		{
			_m_cnt = 0;
		}

		[[nodiscard]] const cnt_type& cnt()const noexcept
		{
			return _m_cnt;
		}

		constexpr ref_count& operator=(const ref_count& other)
		{
			_m_cnt = other._m_cnt;
			return *this;
		}

		constexpr ref_count& operator=(ref_count&& other)noexcept
		{
			_m_cnt = other._m_cnt;
			other._m_cnt = 0;
			return *this;
		}

		constexpr ref_count& operator++()
		{
			++_m_cnt;
			return *this;
		}

		inline ref_count operator++(int)
		{
			auto _Tmp = *this;
			++(*this);
			return *this;
		}

		inline ref_count& operator+=(const cnt_type step)
		{
			_m_cnt += step;
			return *this;
		}

		[[nodiscard]] inline ref_count operator+(const cnt_type cnt)
		{
			auto _Tmp = *this;
			return _Tmp += cnt;
		}

		inline ref_count& operator--()
		{
			--_m_cnt;
			return *this;
		}

		[[nodiscard]] inline ref_count operator--(int)
		{
			auto _Tmp = *this;
			--(*this);
			return _Tmp;
		}

		inline ref_count& operator-=(const cnt_type step)
		{
			_m_cnt -= step;
			return *this;
		}

		[[nodiscard]] inline ref_count operator-(const cnt_type cnt)
		{
			auto _Tmp = *this;
			return _Tmp -= cnt;
		}

		template<typename Integer>
		[[nodiscard]] inline bool operator==(const Integer other)const noexcept
		{
			return static_cast<bool>(_m_cnt == (cnt_type)other);
		}

		[[nodiscard]] inline bool operator==(const ref_count& other)const noexcept
		{
			return static_cast<bool>(_m_cnt == other._m_cnt);
		}

		[[nodiscard]] inline bool operator!=(ref_count const& other)const noexcept
		{
			return static_cast<bool>(_m_cnt != other._m_cnt);
		}

		inline operator cnt_type()noexcept
		{
			return _m_cnt;
		}

	private:
		zuck::size_t _m_cnt;
	};

}